#pragma once
#include <iostream>
#include "Task.hpp"
#include <pthread.h>
#include <queue>
#define NUM 6
template <class T>
class ThreadPool
{
private:
    ThreadPool(int num = NUM)
        : _num(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    ThreadPool(const ThreadPool<T> &t) = delete;
    ThreadPool<T> &operator=(const ThreadPool<T> &t) = delete;

public:
    static ThreadPool<T> *getThreadPool()
    {
        static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
        if (_single_instance == nullptr)
        {
            pthread_mutex_lock(&lock);
            if (_single_instance == nullptr)
            {
                _single_instance = new ThreadPool<T>(NUM);
                _single_instance->Init();
            }
            pthread_mutex_unlock(&lock);
        }
        return _single_instance;
    }
    void Lock()
    {
        pthread_mutex_lock(&_mutex);
    }
    void Unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void CondWait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    void Signal()
    {
        pthread_cond_signal(&_cond);
    }
    static void *ThreadRoutin(void *args)
    {
        pthread_detach(pthread_self());
        ThreadPool<T> *ptr = static_cast<ThreadPool<T> *>(args);
        while (true)
        {
            ptr->Lock();
            while (ptr->_taskq.empty())
            {
                ptr->CondWait();
            }
            T task = ptr->pop();
            ptr->Unlock();
            task.Start();
        }

        return nullptr;
    }
    void Init()
    {
        for (int i = 0; i < _num; i++)
        {
            pthread_t tid;
            if (pthread_create(&tid, nullptr, ThreadRoutin, this) != 0)
            {
                std::cout << "create thread error" << std::endl;
            }
        }
    }
    void push(const T &date)
    {
        Lock();
        _taskq.push(date);
        Unlock();
        Signal();
    }
    T pop()
    {
        T out_date = _taskq.front();
        _taskq.pop();
        return out_date;
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    std::queue<T> _taskq;
    int _num;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
    static ThreadPool<T> *_single_instance; // 设计为单例模式；
};
template <class T>
ThreadPool<T> *ThreadPool<T>::_single_instance = nullptr;